package com.youtills.resource;

import com.youtills.core.lang.NumberUtil;
import com.youtills.core.lang.ObjectUtil;
import com.youtills.core.lang.StringUtil;

import java.util.HashMap;
import java.util.HashSet;

/**
 * TODO - !!!doc me!!!
 *
 * @author ravi.chiluveru
 * @since 1.0 (3/6/15)
 */
public final class Relationship {

    private static final Manager manager = new Manager();

    private final long relationshipId;
    private final String relationshipName;
    private final ResourceType leftResourceType;
    private final ResourceType rightResourceType;
    private final Integer leftMinCount;
    private final Integer leftMaxCount;
    private final Integer rightMinCount;
    private final Integer rightMaxCount;
    private final Boolean allowDuplicate;

    public Relationship(final long relationshipId, final String relationshipName,
                        final ResourceType leftResourceType, final Integer leftMinCount, final Integer leftMaxCount,
                        final ResourceType rightResourceType, final Integer rightMinCount, final Integer rightMaxCount,
                        final Boolean allowDuplicate) {
        this.relationshipId = relationshipId;
        this.relationshipName = relationshipName;
        this.leftResourceType = leftResourceType;
        this.rightResourceType = rightResourceType;
        this.leftMinCount = leftMinCount;
        this.leftMaxCount = leftMaxCount;
        this.rightMinCount = rightMinCount;
        this.rightMaxCount = rightMaxCount;
        this.allowDuplicate = allowDuplicate;
    }

    public static class Builder {
        private long relationshipId;
        private String relationshipName;
        private ResourceType leftResourceType;
        private ResourceType rightResourceType;
        private Integer leftMinCount;
        private Integer leftMaxCount;
        private Integer rightMinCount;
        private Integer rightMaxCount;
        private Boolean allowDuplicate;

        public long getRelationshipId() {
            return relationshipId;
        }

        public Builder setRelationshipId(final long relationshipId) {
            this.relationshipId = relationshipId;
        }

        public String getRelationshipName() {
            return relationshipName;
        }

        public Builder setRelationshipName(final String relationshipName) {
            this.relationshipName = relationshipName;
        }

        public ResourceType getLeftResourceType() {
            return leftResourceType;
        }

        public Builder setLeftResourceType(final ResourceType leftResourceType) {
            this.leftResourceType = leftResourceType;
            return this;
        }

        public ResourceType getRightResourceType() {
            return rightResourceType;
        }

        public Builder setRightResourceType(final ResourceType rightResourceType) {
            this.rightResourceType = rightResourceType;
            return this;
        }

        public Integer getLeftMinCount() {
            return leftMinCount;
        }

        public Builder setLeftMinCount(final Integer leftMinCount) {
            this.leftMinCount = leftMinCount;
            return this;
        }

        public Integer getLeftMaxCount() {
            return leftMaxCount;
        }

        public Builder setLeftMaxCount(final Integer leftMaxCount) {
            this.leftMaxCount = leftMaxCount;
            return this;
        }

        public Integer getRightMinCount() {
            return rightMinCount;
        }

        public Builder setRightMinCount(final Integer rightMinCount) {
            this.rightMinCount = rightMinCount;
            return this;
        }

        public Integer getRightMaxCount() {
            return rightMaxCount;
        }

        public Builder setRightMaxCount(final Integer rightMaxCount) {
            this.rightMaxCount = rightMaxCount;
            return this;
        }

        public Boolean getAllowDuplicate() {
            return allowDuplicate;
        }

        public Builder setAllowDuplicate(final Boolean allowDuplicate) {
            this.allowDuplicate = allowDuplicate;
            return this;
        }
    }

    public static Relationship registerRelationship(Builder builder) {
        return manager.registerRelationship(builder);
    }

    public static Relationship getRelationship(long relationship) {
        return manager.getRelationship(relationship);
    }

    public static <T extends Resource> Relationship getRelationship(Class<T> resourceClass) {
        return manager.getRelationship(resourceClass);
    }

    private static class Manager<T extends Resource> {
        final HashMap<String, Relationship> relationshipsByName;
        final HashMap<Long, Relationship> relationshipsById;
        private Manager() {
            relationshipsByName = new HashMap<>();
            relationshipsById = new HashMap<>();
        }

        synchronized Relationship registerRelationship(Builder builder) {

            if(!NumberUtil.isGreaterThanZero(builder.relationshipId) || StringUtil.isEmpty(builder.relationshipName)) {
                throw new RuntimeException("RelationshipId & relationshipNames are required");
            }

            Relationship byName = relationshipsByName.get(builder.relationshipName);
            Relationship byId = relationshipsByName.get(builder.relationshipId);

            if (byName != null || byId != null) {
                throw new RuntimeException("Resource Type already registered");
            }

            return null;
        }

        Relationship getRelationship(long type) {
            return relationshipsById.get(type);
        }
        Relationship<T> getRelationship(Class<T> resourceClass) {
            return relationships.get(resourceClass);
        }

        private long type(String className) {
            //TODO - get it from persisted
            if("com.youtills.domain.contact.Address".equals(className)) {
                return 101;
            } else if("com.goodedeeds.domain.resource.School".equals(className)) {
                return 100001;
            } else if("com.goodedeeds.domain.resource.Project".equals(className)) {
                return 100002;
            } else if("com.goodedeeds.domain.resource.Vendor".equals(className)) {
                return 100003;
            }
            return -1;
        }
    }
}
